using System;
using System.Collections;
using System.Collections.Generic;
using Artifact.Network;
using Artifact.Network.Buffer;
using Artifact.Network.Coder;

//namespace client.network.protocol
namespace Artifact.Unity.Network
{
    public interface AbstractDTO {
        Dictionary<object,object> toMap(Dictionary<object,object> map);
        object forMap(Dictionary<object,object> map);
    }
    /// <summary>
    /// 玩家简单信息
    /// <summary>
    public class PlayerInfoDTO : AbstractDTO{
        /// <summary>
        /// 用户ID
        /// </summary>
        public long Uid { get; set; }
        /// <summary>
        /// 玩家ID
        /// </summary>
        public long Pid { get; set; }
        /// <summary>
        /// 昵称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 等级
        /// </summary>
        public int Lvl { get; set; }
        /// <summary>
        /// 经验
        /// </summary>
        public int Exp { get; set; }
        /// <summary>
        /// 头像
        /// </summary>
        public int Icon { get; set; }
        /// <summary>
        /// 类型
        /// </summary>
        public int Type { get; set; }

        public virtual Dictionary<object,object> toMap(Dictionary<object,object> map){
            map.Add(115792, DtoSerializationProvider.tryEncoder(this.Uid));
            map.Add(110987, DtoSerializationProvider.tryEncoder(this.Pid));
            map.Add(3373707, DtoSerializationProvider.tryEncoder(this.Name));
            map.Add(107554, DtoSerializationProvider.tryEncoder(this.Lvl));
            map.Add(100893, DtoSerializationProvider.tryEncoder(this.Exp));
            map.Add(3226745, DtoSerializationProvider.tryEncoder(this.Icon));
            map.Add(3575610, DtoSerializationProvider.tryEncoder(this.Type));
            return map;
        }
        public virtual object forMap(Dictionary<object,object> map){
            this.Uid = (long)DtoSerializationProvider.tryDecoder(CommonTool.get(map,115792,this.Uid));
            this.Pid = (long)DtoSerializationProvider.tryDecoder(CommonTool.get(map,110987,this.Pid));
            this.Name = (string)DtoSerializationProvider.tryDecoder(CommonTool.get(map,3373707,this.Name));
            this.Lvl = (int)DtoSerializationProvider.tryDecoder(CommonTool.get(map,107554,this.Lvl));
            this.Exp = (int)DtoSerializationProvider.tryDecoder(CommonTool.get(map,100893,this.Exp));
            this.Icon = (int)DtoSerializationProvider.tryDecoder(CommonTool.get(map,3226745,this.Icon));
            this.Type = (int)DtoSerializationProvider.tryDecoder(CommonTool.get(map,3575610,this.Type));
            return this;
        }
    }

    /// <summary>
    /// 玩家信息
    /// <summary>
    public class PlayerDTO : AbstractDTO{
        /// <summary>
        /// 基本信息
        /// </summary>
        public PlayerInfoDTO PlayerInfo { get; set; }

        public virtual Dictionary<object,object> toMap(Dictionary<object,object> map){
            map.Add(2095520559, DtoSerializationProvider.tryEncoder(this.PlayerInfo));
            return map;
        }
        public virtual object forMap(Dictionary<object,object> map){
            this.PlayerInfo = (PlayerInfoDTO)DtoSerializationProvider.tryDecoder(CommonTool.get(map,2095520559,this.PlayerInfo));
            return this;
        }
    }









    public class PlayerModule{
        public const int ENTER_GAME = 450960106;
        public const int NOTIFY_PLAYER = 450970506;

        public static void disp(Packet packet) {
            int command = (int)packet.Head[NetworkHeader.COMMAND];
            int module = command >> 16;
            int method = module << 16 ^ command;
            switch (method) {
                case 6890:
                    _enterGame(packet);
                    break;
                case 17290:
                    _notifyPlayer(packet);
                    break;
            }
        }


        /// <summary>
        /// 进入游戏
        /// </summary>
        public static void enterGame(NetClient client, string loginServerId, string token,EnterGameListener listener) {
            Packet packet = new Packet();
            string messageId = System.Guid.NewGuid().ToString("N");
            packet.Head.Add(NetworkHeader.ID, messageId);
            packet.Head.Add(NetworkHeader.COMMAND, 450960106);
            packet.Head.Add(NetworkHeader.MODULE, 6881);
            packet.Head.Add(NetworkHeader.METHOD, 6890);
            packet.Head.Add(NetworkHeader.TYPE, NetworkHeader.TYPE_DEFAULT);

            packet.Body.Add(451300935, DtoSerializationProvider.tryEncoder(loginServerId));

            packet.Body.Add(110541305, DtoSerializationProvider.tryEncoder(token));

            client.AsyncSend(packet);

            // 注册监听
            if(listener!=null){
                ProtocolLListener.registerRequestListener(messageId,listener);
            }
        }

        /// <summary>
        /// 进入游戏-解码
        /// </summary>
        private static void _enterGame(Packet packet) {
            string messageId = (string)packet.Head[NetworkHeader.ID];
            Delegate listener = ProtocolLListener.getRequestListener(messageId);
            if(listener!=null){
                int _code = (int)packet.Head[NetworkHeader.STATUS];
                PlayerDTO player = null;
                int index = 0;
                if(_code == 0)
                {
                    player = (PlayerDTO)DtoSerializationProvider.tryDecoder(CommonTool.get(packet.Body,-985752863,player));
                    index = (int)DtoSerializationProvider.tryDecoder(CommonTool.get(packet.Body,100346066,index));
                }
                else
                {
                    ProtocolLListener.execErrorListener(_code, packet);
                }
                // 执行监听
                ((EnterGameListener)listener)(_code, player, index);
                // 移除监听
                ProtocolLListener.removeRequestListener(messageId);
            }
        }

        /// <summary>
        /// 进入游戏-监听
        /// </summary>
        public delegate void EnterGameListener(int _code, PlayerDTO player, int index);

        /// <summary>
        /// 推送-解码
        /// </summary>
        private static void _notifyPlayer(Packet packet) {
            int command = (int)packet.Head[NetworkHeader.COMMAND];
            Delegate listener = ProtocolLListener.getNotifyListener(command);
            if(listener!=null){
                string loginServerId = "";
                string token = "";

                loginServerId = (string)DtoSerializationProvider.tryDecoder(packet.Body[451300935]);
                token = (string)DtoSerializationProvider.tryDecoder(packet.Body[110541305]);
                // 执行监听
                ((NotifyPlayerListener)listener)(loginServerId ,token);
            }

        }


        /// <summary>
        /// 推送-监听
        /// </summary>
        public delegate void NotifyPlayerListener(string loginServerId ,string token);
    }

    // 消息路由
    public static class _Dispatcher {
        public static void disp(Packet packet) {
            // 取得模块ID
            int command = (int)packet.Head[NetworkHeader.COMMAND];
            int module = command >> 16;
            switch (module)
            {
                case 6881:
                    PlayerModule.disp(packet);
                    break;
                default:
                    break;
            }
        }
    }


    public class DtoSerializationProvider{
        private delegate AbstractDTO createDTO();

        static Dictionary<int, createDTO> cache = new Dictionary<int, createDTO>();
        static Dictionary<string, int> codes = new Dictionary<string, int>();
        static DtoSerializationProvider()
        {
            // 玩家简单信息
            cache.Add(1102355472,() => new PlayerInfoDTO());
            // 玩家信息
            cache.Add(131897118,() => new PlayerDTO());

            // 玩家简单信息
            codes.Add("PlayerInfoDTO",1102355472);
            // 玩家信息
            codes.Add("PlayerDTO",131897118);
        }

        // 尝试编码
        public static object tryEncoder(object obj)
        {
            if (obj is AbstractDTO)
            {
                string typeName = obj.GetType().Name;
                if(codes.ContainsKey(typeName)){
                    int structCode = codes[typeName];
                    Dictionary<object, object> dict = new Dictionary<object, object>();
                    dict.Add(NetworkHeader.STRUCT_CODE,structCode);
                    return ((AbstractDTO)obj).toMap(dict);
                }
            }
            return obj;
        }

        // 尝试解码
        public static object tryDecoder(object obj)
        {
            if (obj is Dictionary<object, object>)
            {
                Dictionary<object, object> dict = (Dictionary<object, object>)obj;
                if (dict.ContainsKey(NetworkHeader.STRUCT_CODE))
                {
                    int structCode = (int)dict[NetworkHeader.STRUCT_CODE];
                    if (DtoSerializationProvider.cache.ContainsKey(structCode))
                    {
                        AbstractDTO dto = cache[structCode]();
                        return dto.forMap(dict);
                    }
                }
            }
            return obj;
        }
    }

    /**
    public class ArtifactProtocolStreamBuffer : ArtifactStreamBuffer
    {
        public const int STRUCT_CODE = 183928832;

        public ArtifactProtocolStreamBuffer(byte[] bytes = null) : base(bytes)
        {

        }

        public override void WriteObject(object value)
        {
            if (value is AbstractDTO)
            {
                Dictionary<object,object> table = new Dictionary<object,object>();
                ((AbstractDTO)value).toMap(table);
                table.Add(STRUCT_CODE, DtoSerializationProvider.structCode(value.GetType().Name));
                WriteDict(table);
            }
            else
            {
                base.WriteObject(value);
            }
        }

        public override object ReadObject()
        {
            MarkReaderIndex();
            byte tag = Read();
            ResetReaderIndex();
            if (tag == ArtifactBufferCoder.DICT || ArtifactBufferCoder.DICT_SUB_TYPE.ContainsVal(tag))
            {
                Dictionary<object,object> map = ReadDict();
                if (map.ContainsKey(STRUCT_CODE))
                {
                    int structCode = (int)map[STRUCT_CODE];
                    AbstractDTO dto = DtoSerializationProvider.create(structCode);
                    return dto.forMap(map);
                }
                else
                {
                    return map;
                }

            }
            else {
                return base.ReadObject();
            }
        }
    }

    public class SimpleDecoder : Decoder
    {
        public Packet Handler(NetClient client, byte[] data)
        {
            using (ByteBuffer byteBuffer = new ArtifactProtocolStreamBuffer(data))
            {
                Packet packet = new Packet();
                packet.ForByteBuff(byteBuffer);
                return packet;
            }
        }
    }

    public class SimpleEncoder : Encoder
    {
        public byte[] Handler(NetClient client, Packet packet)
        {
            using (ByteBuffer byteBuffer = new ArtifactProtocolStreamBuffer())
            {
                byteBuffer.MarkWriterIndex();
                byteBuffer.Write(new byte[4]);
                packet.ToByteBuff(byteBuffer);
                int length = (int)byteBuffer.GetLength();
                byteBuffer.ResetWriterIndex();
                byteBuffer.Write(BufferUtil.GetByte(length - 4));
                return byteBuffer.ToArray();
            }
        }
    }
    */
    public class NetworkHeader
    {
        public const int STRUCT_CODE = 183928832;


        /** 唯一表示 */
        public const int ID = 0;
        /** 命令 */
        public const int COMMAND = 1;
        /** 状态 */
        public const int STATUS = 2;
        /** 模块 */
        public const int MODULE = 3;
        /** 方法 */
        public const int METHOD = 4;
        /** 类型 */
        public const int TYPE = 5;
        /** 标签 */
        public const int TAG = 6;

        /** 后续可扩展加密方式，验证方式、校验和等等 */












        /** 类型-默认包 */
        public const int TYPE_DEFAULT = 1;
        /** 类型-心跳包 */
        public const int TYPE_HEARTBEAT = 2;
        /** 类型-确认包 */
        public const int TYPE_ACK = 3;
    }

    public delegate void ErrorListener(int _code, Packet packet);

    public class ProtocolLListener
    {

        private static Hashtable request = new Hashtable();

        private static Hashtable notify = new Hashtable();

        private static ErrorListener errorListener = null;

        public static void registerErrorListener(ErrorListener errorListener)
        {
            ProtocolLListener.errorListener = errorListener;
        }

        public static void removeErrorListener()
        {
            ProtocolLListener.errorListener = null;
        }

        public static void execErrorListener(int _code, Packet packet) {
            if (errorListener != null) {
                errorListener(_code, packet);
            }
        }

        public static void registerNotifyListener(int command, Delegate @delegate)
        {
            notify.Add(command, @delegate);
        }

        public static void registerRequestListener(string messageId, Delegate @delegate)
        {
            request.Add(messageId, @delegate);
        }

        public static void removeNotifyListener(int command)
        {
            notify.Remove(command);
        }

        public static void removeRequestListener(string messageId)
        {
            request.Remove(messageId);
        }

        public static Delegate getNotifyListener(int command)
        {
            return (Delegate)notify[command];
        }

        public static Delegate getRequestListener(string messageId)
        {
            return (Delegate)request[messageId];
        }

        public static void clearNotifyListener()
        {
            notify.Clear();
        }

        public static void clearRequestListener()
        {
            request.Clear();
        }
    }

    public class CommonTool
    {
        public static object get(Dictionary<object, object> map, object key, object val)
        {
            if (map.ContainsKey(key)) {
                return map[key];
            }
            return val;
        }
    }
}